package org.spring.boot.fusion.auth.server.business.service.impl;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.spring.boot.fusion.auth.server.business.service.FusionTokenCrudService;
import org.spring.boot.fusion.common.constant.ConstantAttribute;
import org.spring.boot.fusion.common.exception.ServiceErrorStatus;
import org.spring.boot.fusion.common.exception.ServiceRunTimeException;
import org.spring.boot.fusion.security.properties.FusionTokenProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2RequestValidator;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestValidator;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Service;
@Service
public class FusionTokenCrudServiceImpl implements FusionTokenCrudService {

	@Autowired
	private TokenStore tokenStore;
	@Autowired
	private ClientDetailsService clientDetailsService;
	@Autowired
	private FusionTokenProperties tokenConfigProperties;
	@Autowired
	private AuthorizationServerTokenServices authorizationServerTokenServices;
	private OAuth2RequestValidator oAuth2RequestValidator = new DefaultOAuth2RequestValidator();

	@Override
	public String deleteToken(HttpServletRequest request) {
		String authorization = request.getHeader("Authorization");
		if (authorization!=null && authorization.length()>0 && !authorization.equalsIgnoreCase(ConstantAttribute.NULL)) {
			String[] split = authorization.split(ConstantAttribute.BEARER);
			String tokenValue = split[split.length-1].trim();
			if (tokenValue!=null && tokenValue.length() > 0 && !tokenValue.equalsIgnoreCase(ConstantAttribute.NULL)) {
				OAuth2AccessToken readAccessToken = tokenStore.readAccessToken(tokenValue);
				if (readAccessToken != null) {
					tokenStore.removeAccessToken(readAccessToken);
					return ConstantAttribute.SUCCESS_SATE;
				}
			}
		}
		return ConstantAttribute.FAILURE_SATE;
	}

	@Override
	public Map<String, Object> refreshToken(String refresh_token) {
		if (refresh_token == null || refresh_token.equalsIgnoreCase(ConstantAttribute.NULL) || refresh_token.length() == 0) {
			throw new ServiceRunTimeException(ServiceErrorStatus.TOKEN_ISNULL.message());
		}
		Map<String, String> parameters = new HashMap<String, String>();
		parameters.put("grant_type", "refresh_token");
		parameters.put("refresh_token", refresh_token);
		String clientId = tokenConfigProperties.getUsername();

		ClientDetails authenticatedClient = clientDetailsService.loadClientByClientId(clientId);

		TokenRequest tokenRequest = new TokenRequest(parameters, clientId, authenticatedClient.getScope(),
				parameters.get("grant_type"));

		if (authenticatedClient != null) {
			oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);
		}

		if (isAuthCodeRequest(parameters)) {
			if (!tokenRequest.getScope().isEmpty()) {
				tokenRequest.setScope(Collections.<String>emptySet());
			}
		}

		if (isRefreshTokenRequest(parameters)) {
			tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE)));
		}

		OAuth2AccessToken token = authorizationServerTokenServices.refreshAccessToken(parameters.get("refresh_token"),
				tokenRequest);

		if (token == null) {
			throw new ServiceRunTimeException(ServiceErrorStatus.TOKEN_ISNULL);
		}
		Map<String, Object> hashMap = new HashMap<String, Object>();
		hashMap.put("access_token", token.getValue());
		hashMap.put("refresh_token", token.getRefreshToken().getValue());
		hashMap.put("expires_in", token.getExpiresIn());
		return hashMap;

	}

	private boolean isRefreshTokenRequest(Map<String, String> parameters) {
		return "refresh_token".equals(parameters.get("grant_type")) && parameters.get("refresh_token") != null;
	}

	private boolean isAuthCodeRequest(Map<String, String> parameters) {
		return "authorization_code".equals(parameters.get("grant_type")) && parameters.get("code") != null;
	}

	public void setOAuth2RequestValidator(OAuth2RequestValidator oAuth2RequestValidator) {
		this.oAuth2RequestValidator = oAuth2RequestValidator;
	}

}
